package xj.toolkit.netty.transport.endpoint;

import java.net.SocketAddress;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import xj.toolkit.netty.transport.ProtocolConstants;

public class DefaultServerEndpoint<I> extends AbstractEndpoint<I> implements ServerEndpoint<I> {

	private static final Logger logger = LoggerFactory.getLogger(DefaultServerEndpoint.class);

	protected Channel channel = null;

	@Override
	public void start() {

	}

	@Override
	public void send(I msg) {
		Preconditions.checkArgument(msg != null);

		if (!channel.isOpen()) {
			logger.warn("Channel[{}] ISNOT open. cannot send msg[{}].", channel, msg);
			return;
		}
		
		if (!channel.isWritable()) {
			logger.warn("Channel[{}] ISNOT open. cannot send msg[{}].", channel, msg);
			return;
		}
		
		ChannelFuture future = channel.writeAndFlush(msg);
		future.addListener(new ChannelFutureListener() {
			
			@Override
			public void operationComplete(ChannelFuture future) throws Exception {
				if (!future.isSuccess()) {
					logger.error("Send msg fail.", future.cause());
				}
			}
		});

	}

	@Override
	public void setChannel(Channel channel) {
		Preconditions.checkArgument(channel != null);
		this.channel = channel;
		if (null != objectName && null != mbeanExport) {
			try {
				mbeanExport.getServer().unregisterMBean(objectName);
			} catch (MBeanRegistrationException e) {
				logger.error("setChannel:", e);
			} catch (InstanceNotFoundException e) {
				logger.error("setChannel:", e);
			}
		}
		if (null != mbeanExport) {
			try {
				objectName = new ObjectName(objectNamePrefix + ",channel="
						+ channel.toString().replaceAll(":", "/").replaceAll(",", "").replaceAll("=>", "-"));
				mbeanExport.registerManagedResource(this, objectName);
			} catch (MalformedObjectNameException e) {
				logger.error("setChannel:", e);
			} catch (NullPointerException e) {
				logger.error("setChannel:", e);
			}
		}

	}

	@Override
	public void send(Object req, I response) {
		this.send(response);
	}

	@Override
	public String getProtocol() {
		return ProtocolConstants.PROTOCOL_TCP;
	}

	@Override
	public SocketAddress getRemoteAddress() {
		return channel == null ? null : channel.remoteAddress();
	}

	@Override
	public SocketAddress getLocalAddress() {
		return channel == null ? null : channel.localAddress();
	}

}
